//
//  ContentView.swift
//  PeerTalkPlaygroundWithSPM
//
//  Created by treastrain on 2021/05/14.
//

import SwiftUI
import Foundation
import IOKit
import IOKit.serial
import Swifter

struct MotorParameters  {
    var stepsTotal: Int = 0
    var stepsNow: Int = 0
    var stepsNowString: String = "0"
    var speed: Int = 500
    var speedString: String = "500"
    var position: Int32 = 0
    var errorCode: [UInt8] = []
    var triggerString: String = "54"
    var isEStoped: Bool = false
}


struct ContentView: View {
    
    
    
    @ObservedObject var helper = PeerTalkHelper(a: 1)
    
    @ObservedObject var actionScript = ActionScript()
    
    private var iPhoneManager: IPhoneManager = IPhoneManager()
    
    private var actionQueue: DispatchConcurrentQueue = DispatchConcurrentQueue(label: "ActionQueue")
    
    @State private var pavao_ip: String = "172.18.105.94"
    @State private var pavao_port: String = "20000"
    @ObservedObject var pavaoManager = PavaoManager.instance
    @State private var showAlert = false
    @State private var connectPavao = false
    
    @State private var currentLineError: String = ""
    
    @State private var isAutoCreateFolder: Bool = true
    @State private var autoCreateFolder: URL?
    
    @State private var isRunningActionScript: [Bool] = []
    

    
    @State  private var isShowingActionScriptAlert: Bool = false
    
    @State private var numActionScriptButtonsInARow: Int = 6
    
    @State private var firstActionButtonIndex: Int = 0
    // For Debugs,
    @State private var numChannelText: String = "0"
    @State private var numChannels: Int = 0
    @State private var smAlias: String = ""
    @State private var isShowingDebug: Bool = false
    @State private var motors: [MotorParameters] = []
    @State private var debugManager: SerialMotorManager?
    
    @State private var portString: String = "11001"
    @State private var versionString: String = getAppVersionAndBuild()
    @State private var serverManager: ServerManager = ServerManager()
    
    func callScript(scriptName: String, uuid: String, isShowingMessage: Bool = true, isOneScriptAllowed: Bool = false) -> ScriptStatus  {
        actionScript.uuid = uuid
        var index = -1
        for i in 0..<actionScript.scripts.count {
            if (actionScript.scripts[i].name == scriptName) {
                index = i
                break
            }
        }
        
        if (index == -1) {
            return ScriptStatus.SCRIPT_NOT_FOUND
        }
        if (isOneScriptAllowed) {
            
            for i in 0..<isRunningActionScript.count {
                if (isRunningActionScript[i]) {
                    return ScriptStatus.SCRIPT_RUNNING
                }
            }
        }
        else {
            if (isRunningActionScript[index]) {
                if (isShowingMessage) {
                    isShowingActionScriptAlert = true
                }
                return ScriptStatus.SCRIPT_RUNNING
            }
        }
        
        isRunningActionScript[index] = true
        let queue = DispatchSerialQueue(label: "queue", qos:.userInteractive)
//       queue.async {
        DispatchSerialQueue.global(qos: .userInteractive).async {
            if (isAutoCreateFolder) {
                var isHasIphoneCapture: Bool = false
                for script in actionScript.scripts[index].value {
                    if (script.starts(with: "iPhoneCapture")) {
                        isHasIphoneCapture = true
                        break
                    }
                }
                if (isHasIphoneCapture) {
                    
                    let desktopPath: URL =  FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first!
                    var allImagePath: URL = autoCreateFolder ?? desktopPath.appending( path: "imagePacks")
                    createFolder(at: allImagePath)
                    let imagePath = allImagePath.appending( path: Date.now.ISO8601Format())
                    createFolder(at: imagePath)
                    for device in helper.devices {
                        let soloImagePath = imagePath.appending(path: device.alias)
                        device.imageDir = soloImagePath
                        createFolder(at:soloImagePath)
                    }
                }
            }
            //     ELog.d(String(describing: type(of: self)),#function, actionScript.runScript(scripts: actionScript.scripts[index].value), #line)
            currentLineError = ""
                currentLineError = actionScript.runScript(scripts: actionScript.scripts[index].value)
            if (currentLineError != "") {
                
                    ELog.d(String(describing: type(of: self)), #function, "Action script error \(currentLineError)", #line)
                PavaoManager.instance.saveLog(logLevel: LOG_LEVEL.debug, logContent: "Action script error \(currentLineError)")
            }
            
            isRunningActionScript[index] = false
        }
        
    return ScriptStatus.SUCCESS
    }
    
    init() {
        actionScript.onSendIPhoneMessage = { [self] alias, message in
            let devices = helper.getDeviceByAlias(alias: alias)
            if (devices.count == 1) {
                helper.sendMessage(message: message, device: devices.first!)
            }
            return devices.count
        }
        
      
        
        ELog.setLog(Log())
    }
    
    var body: some View {
        VStack{
            HStack {
                Text(versionString)
                    .font(.subheadline)
                    .foregroundColor(.red)
                
                Toggle(isOn: $isShowingDebug) {
                    Text("Debug mode")
                }
                    Divider()
                Toggle(isOn: $isAutoCreateFolder) {
                    Text("Auto Folder")
                }
                
                    // MARK: BOTTON IMAGE DIR
                    Button(
                        action: { [self] in
                            let panel = NSOpenPanel()
                            panel.canChooseFiles = false
                            panel.canChooseDirectories = true
                            panel.allowsMultipleSelection = false
                            
                            if panel.runModal() == .OK {
                                self.autoCreateFolder = panel.urls.first!
                            }
                            
                        }, label: {
                            Text("Image Folder")
                        })
                    .toggleStyle(CheckboxToggleStyle())
                Text("\(self.autoCreateFolder?.absoluteString ?? "" )")
                Divider()
                TextField("port", text: $portString)
                    .frame(width: 150,height: 50,alignment: .trailing)
                Button(serverManager.isServerAlive() ? "Server Off" : "Server on") {
                    if (serverManager.isServerAlive()) {
                        serverManager.stopServer()
                    } else {
                        if let port = Int(portString) {
                            serverManager.startServer(port: in_port_t(port))
                        }
                    }
                  
                }
                Toggle(isOn: $helper.isSendingToElefante) {
                    Text("Auto Elefante")
                }
                Divider()
                TextField("pavao_ip", text: $pavao_ip)
                    .frame(width: 150,height: 50,alignment: .trailing)
                TextField("pavao_port", text: $pavao_port)
                    .frame(width: 50,height: 50,alignment: .trailing)
                
                Button(action: {
                    showAlert = true
                    DispatchQueue.global(qos: .background).async {
                        pavaoManager.testConnection(pavao_ip, pavao_port) { result in
                            connectPavao = result
                        }
                    }
                }) {
                    Text("connect pavao")
                        .font(.subheadline)
                        .foregroundColor(connectPavao ? .green : .blue)
                }
            }.frame(height: 40)
            .alert(isPresented: $showAlert) {
                Alert(
                    title: Text("tips"),
                    message: Text(connectPavao ? "connect pavao success": "connect pavao failure"),
                    dismissButton: .default(Text("confirm"))
                )
            }
            if (isShowingDebug) {
                List {
                    HStack {
                        TextField("串口名称" , text: $smAlias).onChange(of: smAlias) { newValue in
                            smAlias = newValue
                        }
                        Button("选择") {
                            for i in 0..<actionScript.deviceDescriptors.count {
                                if (actionScript.deviceDescriptors[i].alias == smAlias) {
                                    debugManager = actionScript.deviceDescriptors[i].deviceClass as? SerialMotorManager
                                }
                            }
                        }
                        TextField("输入电机通道数量" , text: $numChannelText).onChange(of: numChannelText) { newValue in
                            numChannelText = newValue
                            if let numChannels = Int(numChannelText) {
                                self.numChannels = numChannels
                                motors = Array.init(repeating: MotorParameters(), count: numChannels)
                            }
                        }
                    }
                    VStack {
                        ForEach(0..<numChannels, id: \.self) { index in
                            
                            HStack {
                                Text("\(index + 1)")
                                
                                TextField("输入电机步长" , text: $motors[index].speedString)
                                Button("设置") {
                                    let index_: UInt8 = UInt8(index + 1)
                                    let speed: Int32 = Int32(motors[index].speedString)!
                                    debugManager?.enableMotor(channel: index_)
                                    debugManager?.setSpeed(channel: index_, speed: speed)
                                }
                                Text("步数：\(motors[index].stepsTotal)")
                                
                                TextField("输入电机步长" , text: $motors[index].stepsNowString)
                                Button("点动") {//MARK: 这是和电机合作 stepsNow 步数
                                    let index_: UInt8 = UInt8(index + 1)
                                    let stepsNow: Int32 = Int32(motors[index].stepsNowString)!
                                    debugManager?.enableMotor(channel: index_)
                                    debugManager?.setSteps(channel: index_, steps: stepsNow)
                                    debugManager?.relativelyMove(channel: index_)
                                    motors[index].stepsTotal += Int(stepsNow)
                                }
                                TextField("Home" , text: $motors[index].triggerString)
                                Button("Home") {
                                    if let trigger: UInt8 = UInt8(motors[index].triggerString) {
                                        let index_: UInt8 = UInt8(index + 1)
                                        debugManager?.enableMotor(channel: index_)
                                        
                                        debugManager?.homeMotor(channel: index_, trigger: trigger)
                                        motors[index].stepsTotal = 0
                                    }
                                    
                                }
                                Button("急停状态") {
                                    
                                        let index_: UInt8 = UInt8(index + 1)
                                    let result = debugManager?.checkForEStop(channel: index_)
                                   motors[index].isEStoped = result!
                                }
                                Text("\( motors[index].isEStoped)")
                                Button("步数清零") {
                                    
                                    motors[index].stepsTotal = 0
                                }
                                Button("清报错") {
                                    let index_: UInt8 = UInt8(index + 1)
                                    debugManager?.clearErrorCode(channel:index_)
                                }
                                Button("获得报错代码") {
                                    let index_: UInt8 = UInt8(index + 1)
                                    motors[index].errorCode = debugManager?.getErrorCode(channel:index_) ?? [0xff, 0xff]
                                }
                                Text("\(motors[index].errorCode)")
                                Button("获得位置") {
                                    
                                        let index_: UInt8 = UInt8(index + 1)
                                    motors[index].position = debugManager?.getPosition(channel:  index_) ?? 99999999
                                }
                                Text("\(motors[index].position)")
                                Button("急停") {
                                    let index_: UInt8 = UInt8(index + 1)
                                    debugManager?.stopMotor(channel:index_)
                                }
                            }
                        }
                    }
                }
            }
            HStack {
                Text("Current line: \(actionScript.currentScript)")
                    .font(.subheadline)
                    .foregroundColor(.blue)
                Divider()
                Text("Current error: \(currentLineError)")
                    .font(.subheadline)
                    .foregroundColor(currentLineError == "" ? .green : .red)
            }.frame(height: 40)
                .onAppear() {
                    serverManager.onScriptChanged = {[self]  scriptName, uuid in
                        callScript(scriptName: scriptName, uuid: uuid, isShowingMessage: false, isOneScriptAllowed: true)
                    }
                }
            HStack {
                Button(action: { [self] in
                    let panel = NSOpenPanel()
                    panel.canChooseFiles = true
                    panel.canChooseDirectories = false
                    panel.allowsMultipleSelection = false
                    
                    if panel.runModal() == .OK {
                        actionScript.loadScripts(path: panel.urls.first!)
                        isRunningActionScript = Array.init(repeating: false, count: actionScript.scripts.count)
                        firstActionButtonIndex = 0
                    }
                }) {
                    Text("Load Action Script") 
                        .font(.system(size: 20)) // Specify font size numerically
                        .foregroundColor(.purple)
                }
                
                Divider()
                
                let isNumActionScriptGreaterInARow: Bool = actionScript.scripts.count > numActionScriptButtonsInARow
                Button(action: {
                    if (firstActionButtonIndex > 0) {
                        firstActionButtonIndex -= 1
                    }
                }) {
                    Text("<")
                        .font(.system(size: 20)) // Specify font size numerically
                        .foregroundColor(.blue)
                }
                .disabled(!isNumActionScriptGreaterInARow)
                
                
                Button(action: {
                    if ((firstActionButtonIndex + numActionScriptButtonsInARow) < (actionScript.scripts.count)) {
                        firstActionButtonIndex += 1
                    }
                }) {
                    Text(">")
                        .font(.system(size: 20)) // Specify font size numerically
                        .foregroundColor(.blue)
                }
                .disabled(!isNumActionScriptGreaterInARow)
                
                let backIndex: Int = isNumActionScriptGreaterInARow ? (firstActionButtonIndex + numActionScriptButtonsInARow) : actionScript.scripts.count
                
            //    ForEach(actionScript.scripts.indices, id: \.self) { index in
                ForEach(firstActionButtonIndex..<backIndex, id: \.self) { index in
                    
                    Button(action: {
                        callScript(scriptName: actionScript.scripts[index].name, uuid: "", isShowingMessage: true)
                    }) {
                        Text("Run \(actionScript.scripts[index].name)")
                            .font(.system(size: 20)) // Specify font size numerically
                            .foregroundColor(.blue)
                    }
                }
            }
            .frame(height: 40)
           .alert(isPresented: $isShowingActionScriptAlert) {
                Alert(
                    title: Text("tips"),
                    message: Text("There's script running!"),
                    dismissButton: .default(Text("confirm"))
                )
            }
        }
        VStack {
     //       UsbmuxdDevice.devicesModifyQueue.sync {
                List {
                    ForEach(Array(zip(helper.devices.indices, helper.devices)), id: \.0) { index, device in
                        VStack {
                            // MARK: FIRST ROW
                            HStack {
                                Text("ID: \(device.deviceID) ")
                                Divider()
                                Text("Location ID: \(device.connectedDeviceProperties["LocationID"] as! Int64) ")
                                Divider()
                                Text("Serial Number: \(device.connectedDeviceProperties["SerialNumber"] as! String) ")
                                Divider()
                                Text("USB Serial Number: \(device.connectedDeviceProperties["USBSerialNumber"] as! String) ")
                            }
                            // MARK: SECOND BLOCK
                            VStack {
                                HStack {
                                    // MARK: BUTTON BLINK
                                    Button(
                                        action: { [self] in
                                            let message = iPhoneManager.messageBlink()
                                            device.send(message: message)
                                            
                                        }, label: {
                                            Text("Blink")
                                        })
                                    
                                    // MARK: TEXT ALIAS
                                    TextField(
                                        "Alias ",
                                        text: $helper.devices[index].alias
                                    )
                                    .textFieldStyle(RoundedBorderTextFieldStyle())
                                }
                                
                                HStack {
                                    // MARK: BOTTON TRIGGER
                                    Button(
                                        action: { [self] in

                                            
                                           // let message = iPhoneManager.messageCameraControl(trigger: true, formula: device.formula, volver: device.volver)

                                            //MARK: 这里是和手机交互
                                            let message = iPhoneManager.messageCameraControl(trigger: true, formula: helper.devices[index].formula, volver: helper.devices[index].volver)

                                            
                                            device.send(message: message)
                                            
                                        }, label: {
                                            Text("Trigger")
                                        })
                                    
                                    // MARK: TEXT FORMULA
                                    TextField(
                                        "Formula ",
                                        text: $helper.devices[index].formula
                                    )
                                    
                                    
                                    // MARK: CHECHBOX VOLVER
                                    Toggle(isOn: $helper.devices[index].volver) {
                                        Text("Volver")
                                    }
                                }
                                
                                HStack {
                                    // MARK: BOTTON IMAGE DIR
                                    Button(
                                        action: { [self] in
                                            let panel = NSOpenPanel()
                                            panel.canChooseFiles = false
                                            panel.canChooseDirectories = true
                                            panel.allowsMultipleSelection = false
                                            
                                            if panel.runModal() == .OK {
                                                device.imageDir = panel.urls.first!
                                            }
                                            
                                        }, label: {
                                            Text("Image Folder")
                                        })
                                    .toggleStyle(CheckboxToggleStyle())
                                    Divider()
                                    Text("Image dir: \(device.imageDir.absoluteString)")
                                }
                                HStack {
                                    // MARK: TeXT RESULT
                                    TextField(
                                        "Results",
                                        text: $helper.devices[index].results
                                        
                                    )
                                    .textFieldStyle(RoundedBorderTextFieldStyle())
                                }
                            }
                            
                            .padding()
                            .overlay(
                                RoundedRectangle(cornerRadius: 10)
                                    .stroke(Color(hex: 0x957327), lineWidth: 2)
                            )
                        }
                        .padding()
                        .overlay(
                            RoundedRectangle(cornerRadius: 10)
                                .stroke(Color(hex: 0x1C5E3C), lineWidth: 2)
                        )
                    }
          //      }
                
            }
        }
    }
    
    
    func createFolder(at url: URL) {
            let fileManager = FileManager.default
            if !fileManager.fileExists(atPath: url.path) {
                do {
                    try fileManager.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
                    print("Folder created at: \(url.path)")
                } catch {
                        print("Error creating folder: \(error.localizedDescription)")
                }
            } else {
                print("Folder already exists at: \(url.path)")
            }
        }
    
}

func getAppVersionAndBuild() -> String {
    let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown Version"
    let buildNumber = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "Unknown Build"
    
    return "Version \(appVersion) (Build \(buildNumber))"
}
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


extension Color {
    init(hex: UInt32) {
        let red = Double((hex & 0xFF0000) >> 16) / 255.0
        let green = Double((hex & 0x00FF00) >> 8) / 255.0
        let blue = Double(hex & 0x0000FF) / 255.0
        self.init(red: red, green: green, blue: blue)
    }
}
